package org.amse.tanks.view;

import org.amse.tanks.model.Model;
import org.amse.tanks.model.ModelConstants;
import org.amse.tanks.objects.Bonus;
import org.amse.tanks.objects.Explosion;
import org.amse.tanks.objects.Shot;
import org.amse.tanks.objects.Tank;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.Iterator;

public class UIView extends JFrame implements View, ModelConstants, UIViewConstants {
    private Model myModel;
    private String str = "";
    private boolean[] flagsBuff = new boolean[6];

    private Image tankUp = null;
    private Image tankDown = null;
    private Image tankLeft = null;
    private Image tankRight = null;

    private Image mapFloor = null;
    private Image mapBrickWall = null;
    private Image mapConcreteWall = null;
    private Image mapGrass = null;
    private Image mapWater = null;
    private Image mapIce = null;

    private Image tankShotUp = null;
    private Image tankShotDown = null;
    private Image tankShotRight = null;
    private Image tankShotLeft = null;

    private Image bonusShot = null;
    private Image bonusFast = null;
    private Image bonusPower = null;

    private Image explosionPic = null;
    private Image explosionTankPic = null;

    public UIView(Model model) {
        super("Tanks");
        if (model == null) {
            System.err.println("UIView: Model is not exist.");
            System.exit(-1);
        }

        setDefaultCloseOperation(EXIT_ON_CLOSE);

        try {
            tankUp = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_TANK_UP_PICTURE));
            tankDown = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_TANK_DOWN_PICTURE));
            tankLeft = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_TANK_LEFT_PICTURE));
            tankRight = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_TANK_RIGHT_PICTURE));

            mapFloor = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_MAP_FLOOR));
            mapBrickWall = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_MAP_BRICK));
            mapConcreteWall = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_MAP_CONCRETE));
            mapGrass = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_MAP_GRASS));
            mapWater = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_MAP_WATER));
            mapIce = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_MAP_ICE));

            tankShotUp = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_TANK_SHOT_UP_PICTURE));
            tankShotDown = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_TANK_SHOT_DOWN_PICTURE));
            tankShotRight = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_TANK_SHOT_RIGHT_PICTURE));
            tankShotLeft = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_TANK_SHOT_LEFT_PICTURE));

            bonusShot = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_BONUS_SHOT_PICTURE));
            bonusFast = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_BONUS_FAST_PICTURE));
            bonusPower = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_BONUS_POWER_PICTURE));

            explosionPic = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_EXPLOSION_PICTURE));
            explosionTankPic = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(UI_VIEW_EXPLOSION_TANK_PICTURE));
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < flagsBuff.length; i++) {
            flagsBuff[i] = false;
        }
        myModel = model;

        addKeyListener(new KeyL());

        add(new MyPanel());

        setSize(myModel.getMapWidth()*UI_VIEW_SIMPLE_OBJECT_SIZE,
                myModel.getMapHeight()*UI_VIEW_SIMPLE_OBJECT_SIZE + 30);
        setVisible(true);
    }

    public void update(Model model) {
        if (model != null) {
            myModel = model;
        }
        repaint();
    }

    class KeyL extends KeyAdapter {
        public void keyPressed(KeyEvent e) {
            switch (e.getKeyChar()) {
                case 'w':
                    flagsBuff[0] = true;
                    break;

                case 'a':
                    flagsBuff[1] = true;
                    break;

                case 's':
                    flagsBuff[2] = true;
                    break;

                case 'd':
                    flagsBuff[3] = true;
                    break;

                case ' ':
                    flagsBuff[4] = true;
                    break;

                case '\n':
                    flagsBuff[5] = true;
                    break;
            }
        }

        public void keyReleased(KeyEvent e) {
            switch (e.getKeyChar()) {
                case 'w':
                    flagsBuff[0] = false;
                    break;

                case 'a':
                    flagsBuff[1] = false;
                    break;

                case 's':
                    flagsBuff[2] = false;
                    break;

                case 'd':
                    flagsBuff[3] = false;
                    break;

                case ' ':
                    flagsBuff[4] = false;
                    break;

                case '\n':
                    flagsBuff[5] = false;
                    break;
            }
        }
    }

    class MyPanel extends JPanel {
        int[][] grassBuffer = new int [2][myModel.getMapHeight()*myModel.getMapWidth()];
        int grassBufferCounter = 0;

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.black);

            if (myModel.getMapWidth() == 0) {
                return;
            }

            drawMap(g);
            drawTanks(g);
            drawShots(g);
            drawGrass(g);
            drawBonuses(g);
            drawExplosions(g);
        }

        void drawMap(Graphics g) {
            for (int i = 0; i < myModel.getMapHeight(); i++) {      //painting map
                for (int j = 0; j < myModel.getMapWidth(); j++) {
                    Image mapType = mapFloor;

                    switch (myModel.getMapValue(j, i)) {
                        case MAP_FLOOR:
                            mapType = mapFloor;
                            break;

                        case MAP_BRICK:
                            mapType = mapBrickWall;
                            break;

                        case MAP_CONCRETE:
                            mapType = mapConcreteWall;
                            break;

                        case MAP_GRASS:
                            //fill grass buffer
                            grassBuffer[0][grassBufferCounter] = j;
                            grassBuffer[1][grassBufferCounter] = i;
                            grassBufferCounter++;
                            break;

                        case MAP_WATER:
                            mapType = mapWater;
                            break;

                        case MAP_ICE:
                            mapType = mapIce;
                            break;
                    }
                    g.drawImage(mapType,
                            j * UI_VIEW_SIMPLE_OBJECT_SIZE,
                            i * UI_VIEW_SIMPLE_OBJECT_SIZE,
                            UI_VIEW_SIMPLE_OBJECT_SIZE,
                            UI_VIEW_SIMPLE_OBJECT_SIZE, null);
                }
            }
        }

        void drawGrass(Graphics g) {
            for (int i = 0; i < grassBufferCounter; i++) {      //grass drawing
                g.drawImage(mapGrass,
                        grassBuffer[0][i] * UI_VIEW_SIMPLE_OBJECT_SIZE,
                        grassBuffer[1][i] * UI_VIEW_SIMPLE_OBJECT_SIZE,
                        UI_VIEW_SIMPLE_OBJECT_SIZE,
                        UI_VIEW_SIMPLE_OBJECT_SIZE, null);
            }
        }

        void drawTanks(Graphics g) {
            Iterator iterator = myModel.getTanksList().iterator();           //putting tanks
            while (iterator.hasNext()) {
                Tank tank = (Tank) iterator.next();
                Image tankSide = tankUp;

                switch (tank.getDirection()) {
                    case UP:
                        tankSide = tankUp;
                        break;

                    case RIGHT:
                        tankSide = tankRight;
                        break;

                    case DOWN:
                        tankSide = tankDown;
                        break;

                    case LEFT:
                        tankSide = tankLeft;
                        break;
                }
                g.drawImage(tankSide,
                        tank.getX() * UI_VIEW_SIMPLE_OBJECT_SIZE,
                        tank.getY() * UI_VIEW_SIMPLE_OBJECT_SIZE,
                        UI_VIEW_COMPLEX_OBJECT_SIZE,
                        UI_VIEW_COMPLEX_OBJECT_SIZE, null);
            }
        }

        void drawShots(Graphics g) {
            Iterator iterator = myModel.getShotsList().iterator();       //putting shots
            while (iterator.hasNext()) {
                Shot shot = (Shot) iterator.next();
                Image shotSide = tankShotUp;

                switch (shot.getDirection()) {
                    case UP:
                        shotSide = tankShotUp;
                        break;

                    case RIGHT:
                        shotSide = tankShotRight;
                        break;

                    case DOWN:
                        shotSide = tankShotDown;
                        break;

                    case LEFT:
                        shotSide = tankShotLeft;
                        break;
                }
                g.drawImage(shotSide,
                        shot.getX() * UI_VIEW_SIMPLE_OBJECT_SIZE,
                        shot.getY() * UI_VIEW_SIMPLE_OBJECT_SIZE,
                        UI_VIEW_SIMPLE_OBJECT_SIZE,
                        UI_VIEW_SIMPLE_OBJECT_SIZE, null);
            }
        }

        void drawBonuses(Graphics g){
            Iterator iterator = myModel.getBonusesList().iterator();       //putting bonuses
            while (iterator.hasNext()) {
                Bonus bonus = (Bonus) iterator.next();
                Image bonusType = bonusShot;

                switch (bonus.getValue()) {
                    case BONUS_SHOT:
                        bonusType = bonusShot;
                        break;

                    case BONUS_FAST:
                        bonusType = bonusFast;
                        break;

                    case BONUS_POWER:
                        bonusType = bonusPower;
                        break;
                }
                g.drawImage(bonusType,
                        bonus.getX() * UI_VIEW_SIMPLE_OBJECT_SIZE,
                        bonus.getY() * UI_VIEW_SIMPLE_OBJECT_SIZE,
                        UI_VIEW_COMPLEX_OBJECT_SIZE,
                        UI_VIEW_COMPLEX_OBJECT_SIZE, null);
            }
        }

        void drawExplosions(Graphics g) {
            Iterator iterator = myModel.getExplosionsList().iterator(); //putting explosions
            while (iterator.hasNext()) {
                Explosion explosion = (Explosion) iterator.next();
                Image explosionType;

                if (explosion.isTankExplosion()) {
                    explosionType = explosionTankPic;
                } else {
                    explosionType = explosionPic;
                }
                g.drawImage(explosionType,
                        explosion.getX() * UI_VIEW_SIMPLE_OBJECT_SIZE,
                        explosion.getY() * UI_VIEW_SIMPLE_OBJECT_SIZE,
                        UI_VIEW_COMPLEX_OBJECT_SIZE,
                        UI_VIEW_COMPLEX_OBJECT_SIZE, null);
            }
        }
    }

    public String getStr() {
        str = "";

        if (flagsBuff[0] == true) {
            str = str.concat(COMMAND_UP_CODE);
        }
        if (flagsBuff[1] == true) {
            str = str.concat(COMMAND_LEFT_CODE);
        }
        if (flagsBuff[2] == true) {
            str = str.concat(COMMAND_DOWN_CODE);
        }
        if (flagsBuff[3] == true) {
            str = str.concat(COMMAND_RIGHT_CODE);
        }
        if (flagsBuff[4] == true) {
            str = str.concat(COMMAND_SHOOT_CODE);
        }
        if (flagsBuff[5] == true) {
            str = str.concat(COMMAND_EXIT_CODE);
        }

        return str;
    }
}